package com.xbongbong.paas.service.async;


import com.alibaba.dingtalk.openapi.exception.OApiException;
import com.alibaba.dingtalk.openapi.helper.DepartmentHelper;
import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.dingtalk.openapi.helper.UserHelper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.message.pojo.dto.ConsistencySyncRabbitMqDTO;
import com.xbongbong.pro.rabbitmq.producer.ConsistencySyncProducer;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.help.CompanyVisibleScopesHelper;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserDepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.UserDepartmentModel;
import com.xbongbong.sys.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * EventChangeReceive异步逻辑
 * @author kaka
 * @date 2023-4-13
 */
@Component("eventChangeReceiveAsync")
public class EventChangeReceiveAsync {

    private static final Logger LOG = LoggerFactory.getLogger(EventChangeReceiveAsync.class);

    @Resource
    private CompanyVisibleScopesHelper companyVisibleScopesHelper;
    @Resource
    private UserModel userModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private UserDepartmentModel userDepartmentModel;
    @Resource
    private ConsistencySyncProducer consistencySyncProducer;

    /**
     * 插入或更新用户列表
     * 对应 org_user_add & org_user_modify
     * @param accessToken
     * @param corpId
     * @param userIds	用户IDjson数组
     * @param saveUserDeparment
     * @throws OApiException
     */
    @Async(value = "eventReceivePool")
    public void orgSaveUser(String accessToken, String corpId, String userIds, boolean saveUserDeparment){
        if(StringUtil.isEmpty(userIds) || "[]".equals(userIds)){
            return;
        }
        try {
            List<String> userIdList = JSON.parseArray(userIds, String.class);
            orgSaveUser(accessToken, corpId, userIdList, saveUserDeparment);
        } catch (Exception e) {
            LOG.error("orgSaveUser方法执行出错", e);
        }

    }

    /**
     * 收到部门添加回调的处理
     * 对应 org_dept_create & org_dept_modify
     * @param accessToken accessToken
     * @param corpId 公司id
     * @param depIds 部门id，可能是多个
     * @throws OApiException
     */
    @Async(value = "eventReceivePool")
    public void orgDeptChange(String accessToken, String corpId, String depIds) throws OApiException, XbbException {
        List<String> depIdList = JSON.parseArray(depIds, String.class);
        for(String depId : depIdList) {
            JSONObject department = DepartmentHelper.getDepartment(accessToken, depId);
            if(department == null || department.getIntValue("errcode") != 0) {
                continue;
            }
            DepartmentEntity dep = departmentModel.getByKeyIgnoreDel(depId, corpId);
            boolean insertDepartment = false;
            String oldDeptManagerUseridListStr = "";
            if(dep == null) {
                dep = new DepartmentEntity();
                dep.setCorpid(corpId);
                //ID要设置,formatDepartmentData的ID获取被注解了
                dep.setId(Long.valueOf(depId));
                insertDepartment = true;
            } else {
                dep.setUpdateTime(DateUtil.getInt());
                oldDeptManagerUseridListStr = dep.getDeptManagerUseridList();
            }
            String newDeptManagerUseridListStr = department.getString("deptManagerUseridList") != null ? department.getString("deptManagerUseridList") : "";

            dep.formatDepartmentData(department);
            //设置del为0
            dep.setDel(0);

            //计算depIdRouter
            String depIdRouter = "|" + dep.getId() + "|";
            if(!dep.getParentId().equals(0L)) {
                DepartmentEntity pDep = departmentModel.getByKey(dep.getParentId() , corpId);
                if(pDep != null) {
                    depIdRouter = pDep.getDepIdRouter() + dep.getId() + "|";
                }
            }
            dep.setDepIdRouter(depIdRouter);


            //此处id不会是0所以不要用save
            if(insertDepartment) {
                departmentModel.insert(dep);
            } else {
                departmentModel.update(dep);
            }

            //对部门管理员进行检查并更新
            updateDeptManagerUsers(accessToken, corpId, oldDeptManagerUseridListStr, newDeptManagerUseridListStr);
        }

    }

    @Async(value = "eventReceivePool")
    public void orgDeptRemove(String corpId, String depIds) {
        LOG.info("准备删除部门数据 : corpid = " + corpId + "====depIds = " + depIds);

        List<Long> depIdList = JSON.parseArray(depIds, Long.class);

        if(depIdList.size() > 0) {
            //标记部门删除
            departmentModel.deleteByKeys(depIdList, corpId);
            //删除部门员工关系
            userDepartmentModel.deleteByDepIds(depIdList, corpId);
        }
    }

    /**
     * 插入或更新用户列表
     * @param accessToken
     * @param corpId
     * @param userIdList	用户IDList
     * @param saveUserDeparment
     * @throws OApiException
     */
    private void orgSaveUser(String accessToken, String corpId, List<String> userIdList, boolean saveUserDeparment) throws XbbException {
        for(String userId : userIdList) {
            if(StringUtil.isEmpty(userId)) {
                continue;
            }
            JSONObject user;
            try{
                user = UserHelper.getUser(accessToken, userId, corpId);
            } catch (Exception oe) {
                LOG.error("获取用户信息/user/get时出错，userId=" + userId, oe);
                continue;
            }
            if (user == null || user.getIntValue("errcode") != 0) {
                LOG.warn("UserHelper.getUser 出错 : corpid = " + corpId + " userId=" + userId);
                continue;
            }
            //根据用户JSONObject构建用户实体，插入或者更新数据库记录
            saveUser(corpId, userId, user, saveUserDeparment);
        }
    }

    /**
     * 注意与ISVReceiveController中同名方法并不相同
     * 根据用户JSONObject构建用户实体，插入或者更新数据库记录,
     * 由于每次更改的用户不会太多，所以考虑每个用户[员工]进行排重的形式。接口读取的是员工详情接口
     * @param corpId
     * @param userId
     * @param user
     * @param saveUserDeparment boolean 是否需要进行员工部门关系插入，在更新用户时不需要进行插入
     */
    private void saveUser(String corpId, String userId, JSONObject user, boolean saveUserDeparment) throws XbbException {

        UserEntity userEntity = userModel.getByKeyIngoreDel(userId, corpId);
        boolean insertUser = false;
        if(userEntity == null) {
            userEntity = new UserEntity();
            userEntity.setCorpid(corpId);
            insertUser = true;
        } else {
            String newName = user.getString("name");
            String oldName = userEntity.getName();
            String newAvatar = user.getString("avatar");
            String oldAvatar = userEntity.getAvatar();

            if(!oldName.equals(newName) || (newAvatar != null && !"".equals(newAvatar.trim()) && !oldAvatar.equals(newAvatar))) {
                String baseUrl = Env.LOCAL_URL;
                if(!StringUtil.isEmpty(baseUrl)) {
                    ConsistencySyncRabbitMqDTO consistencySyncRabbitMqDTO = new ConsistencySyncRabbitMqDTO(corpId, newName, newAvatar, userId);
                    consistencySyncProducer.syncData(consistencySyncRabbitMqDTO, XbbRefTypeEnum.USER);
                    LOG.info("用户名称一致性执行命令入队");

                }
            }
        }
        userEntity.formatUserData(user, null, insertUser);

        //此处id不会是0所以不要用save
        if(insertUser) {
            /*
             * 新加入的用户根据是否在可见范围内，插入时设置不同的del，
             * 若在可见范围内则设置为0,不在可见范围内则设置为2，
             * 因为只处理新增员工，下面的update不做判断 --- kaka
             */
            setDel(userEntity);
            try {
                userModel.insert(userEntity);
            } catch (Exception e) {
                // TODO 出错后后面不应该再执行，找一下这里出错的原因
                LOG.error("saveUser insert error", e);
                return;
            }
        } else {
            userModel.update(userEntity);
        }

        //保存用户部门关系表数据
        if(saveUserDeparment) {
            saveUserDeparment(userEntity, corpId);
        }
    }

    /**
     * 保存用户部门关系表数据
     * @param user
     * @param corpId
     */
    private void saveUserDeparment(UserEntity user, String corpId) throws XbbException {
        if(user == null || StringUtil.isEmpty(corpId)) {
            return;
        }

        String userId = user.getUserId();
        if(StringUtil.isEmpty(userId)) {
            return;
        }

        Map<Long, UserDepartmentEntity> userDeptsMap = new HashMap<>(16);

        Map<String, Object> param = new HashMap<>(8);
        param.put("corpid", corpId);
        param.put("userId", userId);

        List<UserDepartmentEntity> userDepts = userDepartmentModel.findEntitys(param);
        if(userDepts.size() > 0) {
            for(UserDepartmentEntity userDept : userDepts) {
                userDeptsMap.put(userDept.getDepartmentId(), userDept);
            }
        }

        //将老的部门关系置为del = 1
        userDepartmentModel.deleteByUserId(userId, corpId);

        String orderInDepts = user.getOrderInDepts();
        String isLeaderInDepts = user.getIsLeaderInDepts();
        String department = user.getDepartment();
        //解析
        JSONArray depIds = JSONArray.parseArray(department);
        Map<Long,Long> orderInDeptsJson = JSON.parseObject(orderInDepts, new TypeReference<Map<Long,Long>>(){});
        Map<Long,Boolean> isLeaderInDeptsJson = JSON.parseObject(isLeaderInDepts,  new TypeReference<Map<Long,Boolean>>(){});

        for (int i = 0; i < depIds.size(); i++) {
            Long depId = depIds.getLong(i);
            Long sort = orderInDeptsJson.get(depId);

            int isLeader = (isLeaderInDeptsJson != null && isLeaderInDeptsJson.get(depId) != null && isLeaderInDeptsJson.get(depId)) ? 1 : 0;

            UserDepartmentEntity userDept = userDeptsMap.get(depId);
            boolean userDeptInsert = false;
            if(userDept == null) {
                userDept = new UserDepartmentEntity();
                userDeptInsert = true;
            }
            userDept.setCorpid(corpId);
            userDept.setUserId(userId);
            userDept.setDepartmentId(depId);
            userDept.setIsLeader(isLeader);
            userDept.setSort(sort);

            //更新修改时间
            userDept.setUpdateTime(DateUtil.getInt());
            //将删除标记置为0
            userDept.setDel(0);


            if(userDeptInsert) {
                userDepartmentModel.insert(userDept);
            } else {
                userDepartmentModel.update(userDept);
            }
        }
    }

    /**
     * Method setDel
     * Description:			根据是否在公司可见范围内设置从钉钉同步的员工del值
     * @param userEntity	当前登录人
     * @author 张伟
     * @date 2017/12/8 21:25
     * version: 3.14.1
     * Modified by: kaka version 3.16.1
     */
    private void setDel(UserEntity userEntity) {
        String corpId = userEntity.getCorpid();
        String userId = userEntity.getUserId();

        List<Long> depIds;
        List<String> userIds;
        JSONObject retJson;
        try {
            retJson = companyVisibleScopesHelper.getDingtalkVisibleScopes(corpId);
        } catch (Exception e) {
            LOG.error("setDel getDingtalkVisibleScopes出错", e);
            return;
        }
        String deptVisibleScopes = retJson.getString("deptVisibleScopes");
        String userVisibleScopes = retJson.getString("userVisibleScopes");
        try {
            depIds = JSON.parseArray(deptVisibleScopes, Long.class);
        } catch (Exception e) {
            LOG.error("/dingtalk/syncCompanyConfig deptVisibleScopes List<Long>转化异常", e);
            // 这里转换出错先当做全公司处理
            depIds = new ArrayList<>();
        }

        try {
            userIds = JSON.parseArray(userVisibleScopes, String.class);
        } catch (Exception e) {
            LOG.error("/dingtalk/syncCompanyConfig userVisibleScopes List<String>转化异常" + userVisibleScopes, e);
            userIds = new ArrayList<>();
        }
        LOG.info("useDingtalkVisibleScopes = true : 获取的retJosn = " + retJson.toJSONString());


        if (null == depIds) {
            depIds = new ArrayList<>();
        }
        if (null == userIds) {
            userIds = new ArrayList<>();
        }
        String departments = userEntity.getDepartment();
        List<Long> depIdList = new ArrayList<>();
        if (!StringUtil.isEmpty(departments)) {
            try {
                depIdList = JSONObject.parseArray(departments, Long.class);
            } catch (Exception e) {
                LOG.error("departments解析失败", e);
            }
        }
        //取交集,操作后depIdList会变成交集list,只要判断该list长度是否大于0，即可判断是否有交集
        depIdList.retainAll(depIds);
        //与deptVisibleScopes有交集
        if ((depIds.size() == 0 && userIds.size() == 0) || depIds.contains(1L) || depIdList.size() > 0 || userIds.contains(userId) ) {
            userEntity.setDel(0);
        } else {
            userEntity.setDel(2);
            userEntity.setIsVisible(0);
        }
    }

    /**
     * 更新部门时更新管理员信息时的操作，对新旧管理员信息进行更新
     * @param accessToken
     * @param corpId
     * @param oldDeptManagerUseridListStr
     * @param newDeptManagerUseridListStr
     * @throws OApiException
     */
    private void updateDeptManagerUsers(String accessToken, String corpId, String oldDeptManagerUseridListStr, String newDeptManagerUseridListStr) throws OApiException, XbbException {
        String[] oldDeptManagerUserids = new String[0];
        String[] newDeptManagerUserids = new String[0];
        if(!StringUtil.isEmpty(oldDeptManagerUseridListStr)) {
            oldDeptManagerUserids = oldDeptManagerUseridListStr.split("\\|");
        }
        if(!StringUtil.isEmpty(newDeptManagerUseridListStr)) {
            newDeptManagerUserids = newDeptManagerUseridListStr.split("\\|");
        }
        //Arrays.asList(oldDeptManagerUserids); 返回的是AbstractList 没有实现remove
        List<String> oldDeptManagerUseridList = new ArrayList<String>();
        for(String oldUserids : oldDeptManagerUserids) {
            oldDeptManagerUseridList.add(oldUserids);
        }
        List<String> newDeptManagerUseridList = Arrays.asList(newDeptManagerUserids);
        if(oldDeptManagerUseridList.size() > 0) {
            for(String NDMUserid : newDeptManagerUseridList) {
                if(oldDeptManagerUseridList.contains(NDMUserid)) {
                    oldDeptManagerUseridList.remove(NDMUserid);
                } else {
                    if(StringUtil.isEmpty(NDMUserid)) {
                        continue;
                    }

                    JSONObject user;
                    try{
                        user = UserHelper.getUser(accessToken, NDMUserid, corpId);
                    } catch (Exception e) {
                        LOG.error("UserHelper.getUser 出错 : corpid = " + corpId + " userId=" + NDMUserid, e);
                        continue;
                    }
                    if (user == null || user.getIntValue("errcode") != 0) {
                        LOG.warn("UserHelper.getUser 出错 : corpid = " + corpId + " userId=" + NDMUserid);
                        continue;
                    }
                    //根据用户JSONObject构建用户实体，插入或者更新数据库记录
                    saveUser(corpId, NDMUserid, user, true);
                }
            }

            //将取消管理员的部门员工进行更新
            if(oldDeptManagerUseridList.size() > 0) {
                orgSaveUser(accessToken, corpId, oldDeptManagerUseridList, true);
            }
        } else {
            orgSaveUser(accessToken, corpId, newDeptManagerUseridList, true);
        }
    }
}
